#include "StdAfx.h"
#include "TextureLoader.h" 
#include "d3dUtil.h"


TextureLoader::TextureLoader(void)
{

}

TextureLoader::~TextureLoader(void)
{
	RemoveAllTextures();
}

void TextureLoader::AddTexture(const tstring& key, ID3D10ShaderResourceView* texture)
{
	tstringstream strstr;
	strstr<<_T("Adding Texture ")<<key<<_T("\n");
	OutputDebugString(strstr.str().c_str());
	m_Textures[key]=texture;
}

void TextureLoader::RemoveTexture(const tstring& key)
{
	tstringstream strstr;
	strstr<<_T("Removing Texture ")<<key<<_T("\n");
	OutputDebugString(strstr.str().c_str());
	SafeRelease(m_Textures[key]);
	m_Textures.erase(key);
}

void TextureLoader::RemoveAllTextures()
{
	OutputDebugString(_T("Releasing all ID3DTextures.\n"));
	map<tstring,ID3D10ShaderResourceView*>::iterator it;
	for(it=m_Textures.begin(); it != m_Textures.end();++it)
	{
		SafeRelease((*it).second);
	}
	m_Textures.clear();
}

bool TextureLoader::IsTexturePresent(const tstring& key) const
{
	map<tstring,ID3D10ShaderResourceView*>::iterator it;
	return  m_Textures.find(key) != m_Textures.end();
	return false;
}

ID3D10ShaderResourceView* TextureLoader::GetTexture(ID3D10Device *pD3DDevice, const tstring& Filename) 
{
	if ( IsTexturePresent(Filename))
	{
		OutputDebugString(_T("Using Existing Texture.\n"));
	}
	else
	{
		OutputDebugString(_T("Loading New Texture.\n"));
		ID3D10ShaderResourceView *pTextureRV;
		HRESULT hr = D3DX10CreateShaderResourceViewFromFile( pD3DDevice, Filename.c_str(), NULL, NULL, &pTextureRV, NULL );
		if(hr!=S_OK)
		{
			tstringstream tstrstr;
			tstrstr << _T("Loading texture ") << Filename << _T(" Failed  !!!");
			//MessageBox(0,tstrstr.str().c_str(),_T("ERROR"),0);
			return 0;
		}
		AddTexture(Filename, pTextureRV);
	}
	return m_Textures[Filename];
}

ID3D10ShaderResourceView* TextureLoader::GetCubeMap(ID3D10Device *pD3DDevice, const tstring& key)
{
	if ( IsTexturePresent(key))
	{
		OutputDebugString(_T("Using Existing Cubemap.\n"));
	}
	else
	{
		OutputDebugString(_T("Loading New Cubemap.\n"));
		D3DX10_IMAGE_LOAD_INFO idb;
		idb.MiscFlags = D3D10_RESOURCE_MISC_TEXTURECUBE;

		ID3D10Texture2D *tex;

		HRESULT hr = D3DX10CreateTextureFromFile( pD3DDevice, key.c_str(), &idb, NULL, (ID3D10Resource**)&tex, NULL );
		if(hr!=S_OK)
		{
			tstringstream tstrstr;
			tstrstr << _T("Loading Cubemap ") << key << _T(" Failed  !!!");
			MessageBox(0,tstrstr.str().c_str(),_T("ERROR"),0);
			return 0;
		}
		D3D10_TEXTURE2D_DESC texDesc;
		tex->GetDesc(&texDesc);

		D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
		viewDesc.Format = texDesc.Format;
		viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURECUBE;
		viewDesc.TextureCube.MipLevels = texDesc.MipLevels;
		viewDesc.TextureCube.MostDetailedMip = 0;

		ID3D10ShaderResourceView* rv = 0;
		HR(pD3DDevice->CreateShaderResourceView(tex, &viewDesc, &rv));

		AddTexture(key, rv);

		SafeRelease(tex);
	}
	return m_Textures[key];
}

ID3D10ShaderResourceView* TextureLoader::BuildRandomTex(ID3D10Device *pD3DDevice)
{
	// 
	// Create the random data.
	//
	D3DXVECTOR4 randomValues[1024];

	for(int i = 0; i < 1024; ++i)
	{
		randomValues[i].x = RandF(-1.0f, 1.0f);
		randomValues[i].y = RandF(-1.0f, 1.0f);
		randomValues[i].z = RandF(-1.0f, 1.0f);
		randomValues[i].w = RandF(-1.0f, 1.0f);
	}

    D3D10_SUBRESOURCE_DATA initData;
    initData.pSysMem = randomValues;
	initData.SysMemPitch = 1024*sizeof(D3DXVECTOR4);
    initData.SysMemSlicePitch = 1024*sizeof(D3DXVECTOR4);
	//
	// Create the texture.
	//
    D3D10_TEXTURE1D_DESC texDesc;
    texDesc.Width = 1024;
    texDesc.MipLevels = 1;
    texDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
    texDesc.Usage = D3D10_USAGE_IMMUTABLE;
    texDesc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
    texDesc.CPUAccessFlags = 0;
    texDesc.MiscFlags = 0;
    texDesc.ArraySize = 1;

	ID3D10Texture1D* randomTex = 0;
    HR(pD3DDevice->CreateTexture1D(&texDesc, &initData, &randomTex));
	//
	// Create the resource view.
	//
    D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
	viewDesc.Format = texDesc.Format;
    viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE1D;
    viewDesc.Texture1D.MipLevels = texDesc.MipLevels;
	viewDesc.Texture1D.MostDetailedMip = 0;
	
	ID3D10ShaderResourceView* pRandomTexRV;

    HR(pD3DDevice->CreateShaderResourceView(randomTex, &viewDesc, &pRandomTexRV));

	SafeRelease(randomTex);

	if(m_Textures[_T("RandomTex")] !=0) RemoveTexture(_T("RandomTex"));

	AddTexture(_T("RandomTex"), pRandomTexRV);
	
	return m_Textures[_T("RandomTex")];
}

ID3D10ShaderResourceView* TextureLoader::CreateTexArray(ID3D10Device *pD3DDevice, tstring key, const vector<tstring>& filenames)
{
	//
	// Has this texture already been created?
	//
	for(size_t i = 0; i < m_Textures.size(); ++i)
	{
		if ( IsTexturePresent(key))
		{
			OutputDebugString(_T("Using Existing Texture.\n"));
			return m_Textures[key];
		}
	}

	//
	// Load the texture elements individually from file.  These textures
	// won't be used by the GPU (0 bind flags), they are just used to 
	// load the image data from file.  We use the STAGING usage so the
	// CPU can read the resource.
	//

	UINT arraySize = (UINT)filenames.size();

	vector<ID3D10Texture2D*> srcTex(arraySize, 0);
	for(UINT i = 0; i < arraySize; ++i)
	{
		D3DX10_IMAGE_LOAD_INFO loadInfo;

        loadInfo.Width  = D3DX10_FROM_FILE;
        loadInfo.Height = D3DX10_FROM_FILE;
        loadInfo.Depth  = D3DX10_FROM_FILE;
        loadInfo.FirstMipLevel = 0;
        loadInfo.MipLevels = D3DX10_FROM_FILE;
        loadInfo.Usage = D3D10_USAGE_STAGING;
        loadInfo.BindFlags = 0;
        loadInfo.CpuAccessFlags = D3D10_CPU_ACCESS_WRITE | D3D10_CPU_ACCESS_READ;
        loadInfo.MiscFlags = 0;
        loadInfo.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
        loadInfo.Filter = D3DX10_FILTER_NONE;
        loadInfo.MipFilter = D3DX10_FILTER_NONE;
		loadInfo.pSrcInfo  = 0;

		HR(D3DX10CreateTextureFromFile(pD3DDevice, filenames[i].c_str(), 
			&loadInfo, 0, (ID3D10Resource**)&srcTex[i], 0));
	}

	//
	// Create the texture array.  Each element in the texture 
	// array has the same format/dimensions.
	//

	D3D10_TEXTURE2D_DESC texElementDesc;
	srcTex[0]->GetDesc(&texElementDesc);

	D3D10_TEXTURE2D_DESC texArrayDesc;
	texArrayDesc.Width              = texElementDesc.Width;
	texArrayDesc.Height             = texElementDesc.Height;
	texArrayDesc.MipLevels          = texElementDesc.MipLevels;
	texArrayDesc.ArraySize          = arraySize;
	texArrayDesc.Format             = DXGI_FORMAT_R8G8B8A8_UNORM;
	texArrayDesc.SampleDesc.Count   = 1;
	texArrayDesc.SampleDesc.Quality = 0;
	texArrayDesc.Usage              = D3D10_USAGE_DEFAULT;
	texArrayDesc.BindFlags          = D3D10_BIND_SHADER_RESOURCE;
	texArrayDesc.CPUAccessFlags     = 0;
	texArrayDesc.MiscFlags          = 0;

	ID3D10Texture2D* texArray = 0;
	HR(pD3DDevice->CreateTexture2D( &texArrayDesc, 0, &texArray));

	//
	// Copy individual texture elements into texture array.
	//

	// for each texture element...
	for(UINT i = 0; i < arraySize; ++i)
	{
		// for each mipmap level...
		for(UINT j = 0; j < texElementDesc.MipLevels; ++j)
		{
			D3D10_MAPPED_TEXTURE2D mappedTex2D;
			srcTex[i]->Map(j, D3D10_MAP_READ, 0, &mappedTex2D);
                    
			pD3DDevice->UpdateSubresource(texArray, 
				D3D10CalcSubresource(j, i, texElementDesc.MipLevels),
                0, mappedTex2D.pData, mappedTex2D.RowPitch, 0);

            srcTex[i]->Unmap(j);
		}
	}	

	//
	// Create a resource view to the texture array.
	//
	
	D3D10_SHADER_RESOURCE_VIEW_DESC viewDesc;
	viewDesc.Format = texArrayDesc.Format;
	viewDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2DARRAY;
	viewDesc.Texture2DArray.MostDetailedMip = 0;
	viewDesc.Texture2DArray.MipLevels = texArrayDesc.MipLevels;
	viewDesc.Texture2DArray.FirstArraySlice = 0;
	viewDesc.Texture2DArray.ArraySize = arraySize;

	ID3D10ShaderResourceView* texArrayRV = 0;
	HR(pD3DDevice->CreateShaderResourceView(texArray, &viewDesc, &texArrayRV));

	//
	// Cleanup--we only need the resource view.
	//

	SafeRelease(texArray);

	for(UINT i = 0; i < arraySize; ++i)
		SafeRelease(srcTex[i]); 

	AddTexture(key,texArrayRV);

	return texArrayRV;
}